package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningRecordFormDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.SectionType;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import com.tianji.learning.utils.LearningRecordDelayTaskHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * <p>
 * 学习记录表 服务实现类
 * </p>
 *
 * @author EllieHy
 * @since 2024-05-28
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {
	private final ILearningLessonService lessonService;
	private final CourseClient courseClient;
	private final LearningRecordDelayTaskHandler recordDelayTaskHandler;
	
	@Override
	public LearningLessonDTO queryLearningRecordByCourse(Long courseId) {
		//1/获取当前登录用户id
		Long userId = UserContext.getUser();
		//2.查询课表id 条件用户id和courseId
		LearningLesson lesson = lessonService.lambdaQuery()
				.eq(LearningLesson::getUserId, userId)
				.eq(LearningLesson::getCourseId, courseId).one();
		if (lesson == null) {
			throw new BizIllegalException("该课程未加入课表");
		}
		//3.查询学习记录 条件用户id和lessonId
		List<LearningRecord> recordList = lambdaQuery()
				.eq(LearningRecord::getUserId, userId)
				.eq(LearningRecord::getLessonId, lesson.getId()).list();
		//4.封装数据,返回结果
		LearningLessonDTO dto = new LearningLessonDTO();
		dto.setId(lesson.getId());
		dto.setLatestSectionId(lesson.getLatestSectionId());
		List<LearningRecordDTO> dtoList = BeanUtils.copyList(recordList, LearningRecordDTO.class);
		dto.setRecords(dtoList);
		return dto;
	}
	
	@Override
	public void addLearningRecord(LearningRecordFormDTO recordDTO) {
		//1.获取当前用户ID
		Long userId = UserContext.getUser();
		//2.处理学习记录
		boolean finished;
		if (recordDTO.getSectionType() == SectionType.VIDEO) {
			//2.2提交视频播放记录
			finished = handleVideoRecord(userId, recordDTO);
		} else {
			//2.1提交考试记录
			finished = handleExamRecord(userId, recordDTO);
		}
		//3.处理课表数据
		if (!finished) {
			//如果本小节不是第一次学完不用处理课表数据
			return;
		}
		handleLearningLessonsChanges(recordDTO);
	}
	
	/**
	 * 处理课表数据
	 *
	 * @param recordDTO 需要处理的课表数据
	 */
	private void handleLearningLessonsChanges(LearningRecordFormDTO recordDTO) {
		// 1. 查询课表 learning_lesson 条件learn_id主键
		LearningLesson lesson = lessonService.getById(recordDTO.getLessonId());
		if (lesson == null) {
			throw new BizIllegalException("课表不存在!!!");
		}
		
		// 2. 获取课程信息和判断是否全部完成
		
		CourseFullInfoDTO cInfoDto = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
		if (cInfoDto == null) {
			throw new BizIllegalException("课程不存在!!!");
		}
		Integer sectionNum = cInfoDto.getSectionNum();
		
		
		// 3. 计算是否全部学完
		boolean allSectionsFinished = (lesson.getLearnedSections() + 1 >= sectionNum);
		
		// 4. 更新课表数据
		lessonService.lambdaUpdate()
				.set(allSectionsFinished, LearningLesson::getStatus, LessonStatus.FINISHED)
				.set(lesson.getLearnedSections() == 0, LearningLesson::getStatus, LessonStatus.LEARNING)
				.set(LearningLesson::getLatestSectionId, recordDTO.getSectionId())
				.set(LearningLesson::getLatestLearnTime, recordDTO.getCommitTime())
				.setSql("learned_sections = learned_sections + 1")
				.eq(LearningLesson::getId, lesson.getId())
				.update();
	}
	
	/**
	 * 处理考试记录
	 *
	 * @param userId    用户id
	 * @param recordDTO 需要处理的考试记录
	 * @return boolean
	 */
	private boolean handleExamRecord(Long userId, LearningRecordFormDTO recordDTO) {
		//将dto转换为po
		LearningRecord record = BeanUtils.copyBean(recordDTO, LearningRecord.class);
		record.setUserId(userId);
		record.setFinished(true);//代表本小节已经学习完
		record.setFinishTime(recordDTO.getCommitTime());
		//保存学习记录
		boolean save = save(record);
		if (!save) {
			throw new DbException("新增考试记录失败");
		}
		return true;
	}
	
	/**
	 * 处理视频播放记录
	 *
	 * @param userId    用户id
	 * @param recordDTO 需要处理的视频播放交流
	 * @return boolean
	 */
	private boolean handleVideoRecord(Long userId, LearningRecordFormDTO recordDTO) {
		//查询旧的学习记录  learnRecord userId, lessonId section_id
		LearningRecord learningRecord = queryOldRecord(recordDTO.getLessonId(), recordDTO.getSectionId());
		//判断是否存在
		if (learningRecord == null) {
			//如果不存在新增学习记录
			LearningRecord record = BeanUtils.copyBean(recordDTO, LearningRecord.class);
			record.setUserId(userId);
			//保存学习记录
			boolean result = save(record);
			if (!result) {
				throw new DbException("新增学习记录失败");
			}
			return false;
		}
		
		//如果存在则更新学习记录
		//判断本小节是否是第一次学习完,如果视频进度超过50%就算本小节学习完成
		boolean ifFinish;
		ifFinish = !learningRecord.getFinished() && recordDTO.getMoment() * 2 > recordDTO.getDuration();
		//没有学完,缓存到redis中
		if (!ifFinish) {
			LearningRecord record = new LearningRecord();
			record.setId(learningRecord.getId());
			record.setMoment(recordDTO.getMoment());
			record.setFinished(learningRecord.getFinished());
			record.setLessonId(recordDTO.getLessonId());
			record.setSectionId(recordDTO.getSectionId());
			recordDelayTaskHandler.addLearningRecordTask(record);
			return false;
		}
		//更新学习记录
		boolean result = this.lambdaUpdate()
				.set(LearningRecord::getMoment, recordDTO.getMoment())
				.set(LearningRecord::getFinished, true)
				.set(LearningRecord::getFinishTime, recordDTO.getCommitTime())
				.eq(LearningRecord::getId, learningRecord.getId()).update();
		if (!result) {
			throw new DbException("更新视频学习记录失败");
		}
		//清理缓存
		recordDelayTaskHandler.cleanRecordCache(recordDTO.getLessonId(), recordDTO.getSectionId());
		return true;
	}
	
	private LearningRecord queryOldRecord(Long lessonId, Long sectionId) {
		//1.查询缓存
		LearningRecord cache = recordDelayTaskHandler.readRecordCache(lessonId, sectionId);
		//2.如果命中直接返回
		if (cache != null) {
			return cache;
		}
		//3没有命中查询DB
		LearningRecord dbRecord = lambdaQuery()
				.eq(LearningRecord::getLessonId, lessonId)
				.eq(LearningRecord::getSectionId, sectionId)
				.one();
		if (dbRecord == null) {
			return null;
		}
		//4将查到的数据放入缓存
		recordDelayTaskHandler.addLearningRecordTask(dbRecord);
		return dbRecord;
	}
}
